//
// GPSMapEdit
// (c) Konstantin Galichsky (kg@geopainting.com), 2002-2007
//
// 'Attachments' dialog.
//

# include "StdAfx.h"
# include "Resource.h"
# include "Map.h"
# include "MapView.h"
# include "Scale.h"
# include "Position.h"
# include "Selection.h"
# include "DeleteAttachment.h"
# include "ShowHideAttachment.h"
# include "Dialog.h"
# include "ListView.h"
# include "ParseHelpers.h"
# include "Globals.h"

static
void _LocateAttachment (const file_ref_t * _pFR) {
	UnselectObjects ();

	rect_t rect;
	{
		CCritSec::CLock lock (g_cs);

		for (size_t cKind = 0; cKind < rkMax; ++ cKind) {
			layer_t & layer = g_map.layers [cKind];
			rgns_t & rgns = layer.rgns;
			const size_t cRgns = layer.cRgns;

			for (rgns_t::iterator iRgn = rgns.begin (); iRgn != rgns.end (); ++ iRgn) {
				const rgn_t & rgn = * iRgn;
				if (rgn.IsDeleted () || rgn.pFileRef != _pFR)
					continue;

				rect.Extend (rgn.rectBound);
			
				find_info_t fi;
				fi.pLayer = & layer;
				fi.iRgn = iRgn;
				fi.cElementOrOrigin = -1;
				g_Selection.push_back (fi);
			}
		}

		for (renderers_t::iterator ri = g_map.renderers.begin (); ri != g_map.renderers.end (); ++ ri) {
			renderer_base_t * const pRenderer = * ri;
			if (pRenderer != _pFR)
				continue;

			rect.Extend (pRenderer->rect);

			find_info_t fi;
			fi.pLayer    = NULL;
			fi.pRenderer = pRenderer;
			g_Selection.push_back (fi);

			break;
		}
	}

	SetScale (GetRectScale (rect));
	SetToCenter (point_t (rect.MeanX (), rect.MeanY ()));
	Refresh ();
}

enum {
	catType = 0,
	catTrks = 1,
	catWpts = 2,
	catRts  = 3,
	catShow = 4,
	catFile = 5,
};

class CAttachments : public CDialog {
  public:
	CAttachments () : CDialog (IDD_ATTACHMENTS) {}

	// Override.
	virtual bool OnInit (HWND _hwndFocus);
	virtual void OnDestroy ();
	virtual void OnCommand (WORD _wCmd, WORD _wNotifyCode, HWND _hwndCtl);
	virtual bool OnNotify (int _idCtrl, NMHDR * _pInfo);

  private:
	CListView m_Att;

	void _FillAttachments ();
	file_ref_t * _GetFileRef (size_t _cItem = -1);
	void _UpdateAttachments ();
	void _UpdateShowHide (bool _bVisible);
	void _UpdateButtons (size_t _cItem = -1);

	static int CALLBACK _CompareItems (LPARAM _lItem1, LPARAM _lItem2, LPARAM _lData);
};

int CALLBACK CAttachments::_CompareItems (LPARAM _lItem1, LPARAM _lItem2, LPARAM _lData) {
	const CAttachments * const pThis = reinterpret_cast<const CAttachments *> (_lData);
	const size_t cSortingColumn = pThis->m_Att.GetSortingColumn ();

	char str1 [64], str2 [64];
	ListView_GetItemText (pThis->m_Att, _lItem1, cSortingColumn, str1, 64); 
	ListView_GetItemText (pThis->m_Att, _lItem2, cSortingColumn, str2, 64);

	if (cSortingColumn == catTrks || cSortingColumn == catWpts || cSortingColumn == catRts) {
		// Compare as integers.
		return ParseDecU (str1, str1 + 64) - ParseDecU (str2, str2 + 64);
	} else
		// Compare as strings.
		return ::strcmp (str1, str2);
}

struct fr_data_t {
	size_t cWaypoints;
	size_t cTracks;
	size_t cRoutes;
	fr_data_t () : cWaypoints (0), cTracks (0), cRoutes (0) {}
};

void CAttachments::_FillAttachments () {
	CCritSec::CLock lock (g_cs);

	// Prepare statistics data.
	typedef std::map<const file_ref_t *, fr_data_t> fr2data_t;
	fr2data_t fr2data;

	for (size_t cKind = 0; cKind < rkMax; ++ cKind) {
		layer_t & layer = g_map.layers [cKind];
		rgns_t & rgns = layer.rgns;
		const size_t cRgns = layer.cRgns;

		for (rgns_t::const_iterator iRgn = rgns.begin (); iRgn != rgns.end (); ++ iRgn) {
			const rgn_t & rgn = * iRgn;
			if (rgn.IsDeleted () || ! rgn.IsWTR ())
				continue;

			fr_data_t & data = fr2data [rgn.pFileRef];
			if (rgn.IsWaypoint ())
				++ data.cWaypoints;
			else if (rgn.IsTrack ())
				++ data.cTracks;
			else if (rgn.IsRoute ())
				++ data.cRoutes;
		}
	}

	// Save selection.
	const size_t cSel = ListView_GetSelectionMark (m_Att);
	const LPARAM lParamSel = cSel == -1 ? -1 : GetLParam (m_Att, cSel);

	ListView_DeleteAllItems (m_Att);

	// Tracks/waypoints/routes.
	size_t cItem = 0;
	for (file_refs_t::const_iterator ia = g_map.file_refs.begin (); ia != g_map.file_refs.end (); ++ ia) {
		if (ia->bDeleted || ! ia->bAttachment)
			continue;

		const fr_data_t & data = fr2data [& * ia];

		InsertItem     (m_Att, cItem, reinterpret_cast<LPARAM> (& * ia), "vector");
		SetSubItemText (m_Att, cItem, catTrks, "%d", data.cTracks);
		SetSubItemText (m_Att, cItem, catWpts, "%d", data.cWaypoints);
		SetSubItemText (m_Att, cItem, catRts,  "%d", data.cRoutes);
		SetSubItemText (m_Att, cItem, catShow, ia->bVisible ? "shown" : "hidden");
		SetSubItemText (m_Att, cItem, catFile, "%s", const_cast<char *> (ia->strFileName.c_str ()));

		++ cItem;
	}

	// Raster maps.
	for (renderers_t::const_iterator ri = g_map.renderers.begin (); ri != g_map.renderers.end (); ++ ri) {
		renderer_base_t * const pRenderer = * ri;
		if (pRenderer->bDeleted || pRenderer->bOverlay)
			continue;

		InsertItem     (m_Att, cItem, reinterpret_cast<LPARAM> (pRenderer), "raster");
		SetSubItemText (m_Att, cItem, catTrks, "0");
		SetSubItemText (m_Att, cItem, catWpts, "0");
		SetSubItemText (m_Att, cItem, catRts,  "0");
		SetSubItemText (m_Att, cItem, catShow, pRenderer->bVisible ? "shown" : "hidden");
		SetSubItemText (m_Att, cItem, catFile, "%s", const_cast<char *> (pRenderer->strFileName.c_str ()));

		++ cItem;
	}

	m_Att.Sort ();

	// Restore selection.
	if (lParamSel != -1)
		m_Att.SelectByLParam (lParamSel);
}

file_ref_t * CAttachments::_GetFileRef (size_t _cItem) {
	const size_t cSel = _cItem == -1 ? ListView_GetSelectionMark (m_Att) : _cItem;
	if (cSel == -1)
		return NULL;

	file_ref_t * const pFR = reinterpret_cast<file_ref_t *> (GetLParam (m_Att, cSel));
	assert (pFR);

	return pFR;
}

void CAttachments::_UpdateAttachments () {
	_FillAttachments ();
	Refresh ();
}

void CAttachments::_UpdateShowHide (bool _bVisible) {
	EnableDlgItem (IDC_SHOW_ATTACHMENT, ! _bVisible);
	EnableDlgItem (IDC_HIDE_ATTACHMENT,   _bVisible);
}

void CAttachments::_UpdateButtons (size_t _cItem) {
	file_ref_t * const pFR = _GetFileRef (_cItem);
	if (pFR)
		_UpdateShowHide (pFR->bVisible);
	else {
		EnableDlgItem (IDC_LOCATE_ATTACHMENT, false);
		EnableDlgItem (IDC_SHOW_ATTACHMENT,   false);
		EnableDlgItem (IDC_HIDE_ATTACHMENT,   false);
		EnableDlgItem (IDC_REMOVE_ATTACHMENT, false);
	}
}

bool CAttachments::OnInit (HWND _hwndFocus) {
	// Attachments.
	m_Att.Init (m_hWnd, IDC_MAP_ATTACHMENTS, "Attachments", -1);
	m_Att.SetExtStyle (LVS_EX_FULLROWSELECT | LVS_EX_HEADERDRAGDROP);

	AddColumn (m_Att, catType, "Type");
	AddColumn (m_Att, catTrks, "Trks");
	AddColumn (m_Att, catWpts, "Wpts");
	AddColumn (m_Att, catRts,  "Rts");
	AddColumn (m_Att, catShow, "Show");
	AddColumn (m_Att, catFile, "File path");

	m_Att.SetSorting (_CompareItems, reinterpret_cast<LPARAM> (this));
	_FillAttachments ();
	SetSelection (m_Att, 0);

	AutoSizeColumns (m_Att);
	m_Att.LoadHeaders ();

	// Buttons.
	_UpdateButtons ();

	return true;
}

void CAttachments::OnDestroy () {
	m_Att.SaveHeaders ();
	m_Att.Destroy ();
}

void CAttachments::OnCommand (WORD _wCmd, WORD _wNotifyCode, HWND _hwndCtl) {
	switch (_wCmd) {
		case IDC_SHOW_ATTACHMENT:
		case IDC_HIDE_ATTACHMENT: {
			file_ref_t * const pFR = _GetFileRef ();
			if (pFR) {
				ShowAttachment (pFR, _wCmd == IDC_SHOW_ATTACHMENT, IsRenderer (g_map, * pFR));

				_UpdateShowHide (pFR->bVisible);
				_UpdateAttachments ();
			}

			SetFocus (_wCmd == IDC_SHOW_ATTACHMENT ? IDC_HIDE_ATTACHMENT : IDC_SHOW_ATTACHMENT);

			return;
		}

		case IDC_REMOVE_ATTACHMENT: {
			file_ref_t * const pFR = _GetFileRef ();
			if (pFR)
				DeleteAttachment (pFR, IsRenderer (g_map, * pFR));

			_UpdateAttachments ();
			_UpdateButtons ();

			return;
		}

		case IDC_LOCATE_ATTACHMENT: {
			file_ref_t * const pFR = _GetFileRef ();
			if (pFR) {
				const bool bWasVisible = pFR->bVisible;
				if (! bWasVisible)
					ShowAttachment (pFR, true, IsRenderer (g_map, * pFR));
				_LocateAttachment (pFR);

				if (! bWasVisible) {
					_UpdateShowHide (pFR->bVisible);
					_FillAttachments ();
				}
			}

			return;
		}

		case IDCANCEL:
			EndDialog (0);
			return;
	}
}

bool CAttachments::OnNotify (int _idCtrl, NMHDR * _pInfo) {
	switch (_pInfo->code) {
		case NM_RCLICK:
			m_Att.PopupMenu_OnHeaderRClick (_pInfo);
			break;

		case LVN_COLUMNCLICK: {
			// Save selection.
			const size_t cSel = ListView_GetSelectionMark (m_Att);
			const LPARAM lParamSel = cSel == -1 ? -1 : GetLParam (m_Att, cSel);

			m_Att.Sort_OnColumnClick (_pInfo);

			// Restore selection.
			if (lParamSel != -1)
				m_Att.SelectByLParam (lParamSel);

			break;
		}

		case LVN_ITEMCHANGED: {
			const NMLISTVIEW * const pInfo2 = reinterpret_cast<const NMLISTVIEW *> (_pInfo);
			if (pInfo2->uNewState & LVIS_SELECTED) {
				EnableDlgItem (IDC_REMOVE_ATTACHMENT, true);
				EnableDlgItem (IDC_LOCATE_ATTACHMENT, true);

				_UpdateButtons (pInfo2->iItem);
			}

			break;
		}
	}

	return false;
}

void ShowAttachments () {
	CAttachments ad;
	ad.ShowModal (g_hWnd);
}